-- Ensure we are inspecting the same player we notified for inspection,
-- and that no other AddOn called NotifyInspect after us.
local inspectTainted = inspectTainted
hooksecurefunc("NotifyInspect", function() inspectTainted = true end)

-- Take a snapshot of the players in the current party/raid.
function Orunj:TakeSnapshot()
	print(Orunj.cmdprefix .. "> Taking snapshot...")
	
	-- Get the name of the current player.
	--self.session["player"] = { name = UnitName("player"), me = true, inspected = false }
	local unitId = "player"
	self.session.players[UnitGUID(unitId)] = self:NewOrunjPlayer(unitId) -- Orunj.lua
	
	-- Get the number of raid members.
	local numRaidMembers = GetNumRaidMembers()
	local numPartyMembers = GetNumPartyMembers()
	
	-- Set up the unitId by setting if it's a party or raid.
	local partyOrRaid = numRaidMembers > 0 and "raid" or "party"
	-- print(partyOrRaid)
	
	-- Get the number of players to iterate.
	local numPlayersToIterate = 0
	if numRaidMembers > 0 then 
		numPlayersToIterate = numRaidMembers
	else 
		numPlayersToIterate = numPartyMembers	
	end
	--print("players to iterate: " .. numPlayersToIterate)
	
	-- Make a list of all the players.
	for i=1, numPlayersToIterate do
		local unitId = partyOrRaid .. i
		self.session.players[UnitGUID(unitId)] = self:NewOrunjPlayer(unitId)
	end
	
	self.inspectEnabled = true
	return true
end

-- Get the next player that hasn't been inspected yet.
function Orunj:GetPlayerToInspect()
	for k in pairs(self.session.players) do
		local target = self.session.players[k]
		if not target.inspected then
			return target
		end
	end
	-- Return nil if all players are inspected.
	return nil
end

-- Handle the inspection event fired.
function Orunj:InspectEventFired()
	-- Unregister the event for now, so it doesn't continuously fire.
	self.frame:UnregisterEvent(Orunj.INSPECT_TALENT_EVENT)
	-- The inspection was tainted, so re-do it.
	if inspectTainted then
		self:DoInspect()
	-- The inspection request was successful, so inspect the player.
	else
		local target = self:GetPlayerToInspect()
		print("InspectEventFired. Target: " .. target.name)
		self:InspectPlayer(target)
	end
	-- Re-enable inspection if it has been turned off.
	self.inspectEnabled = true
end

-- Most of the following code was supplied from [http://www.wowinterface.com/forums/showthread.php?p=167585]
-- Inspect players sequentially until all players are properly inspected.
function Orunj:DoInspect()
	local target = self:GetPlayerToInspect()
	-- If there are no more players to inspect, then stop inspecting.
	if not target then
		self.inspectEnabled = false
		print("Inspection complete - all players should be inspected.")
		return
	end
	-- if the player to inspect is me, then proceed directly to the inspection.
	-- (we don't have to wait for the event to fire, since we can just look at
	-- our own client-side stored talents) 
	if target.me then
		-- print("target.me: " .. tostring(target.me))
		self:InspectPlayer(target)
	-- The player to inspect is not me, so we have to notify the WoW server
	-- that we want to inspect the player.	
	elseif CanInspect(target.unitId) then
		NotifyInspect(target.unitId)
		inspectTainted = false
		self.frame:RegisterEvent(Orunj.INSPECT_TALENT_EVENT)
		-- Disable the inspection at this point, to make sure we only inspect
		-- one player at a time. The inspection is re-enabled after a successful
		-- player inspection in InspectPlayer()
		self.inspectEnabled = false
	end
end

-- Inspect the player.
function Orunj:InspectPlayer(target)
	print("InspectPlayer: " .. target.name)
	
	-- Set the boolean flag to make sure we are using GetTalentTabInfo properly.
	-- [http://www.wowwiki.com/API_GetTalentTabInfo]
	local isInspect = not target.me
	
	-- Extract the currently active spec.
	-- info: [http://forums.worldofwarcraft.com/thread.html?topicId=15443405133]
	local activeTalentGroup = GetActiveTalentGroup(isInspect)
	
	-- Keep track of the talent tabs and the amount of points invested in each tab.
	-- This will later be used to infer the player role.
	local numTabs = GetNumTalentTabs(isInspect)
	for t=1, numTabs do
		local tabName, _, tabPointsSpent, _, _ = GetTalentTabInfo(t, isInspect, false, activeTalentGroup) 
		target.talentTrees[tabName] = {}
		
		-- Make a quick easier to use variable to encapsulate target.talentTrees[tabName]
		local currentTree = target.talentTrees[tabName]
		currentTree.points = tabPointsSpent
		
		local numTalents = GetNumTalents(t, isInspect)
		for i=1, numTalents do
			-- [http://www.wowwiki.com/API_GetTalentInfo]
			local name, _, _, _, currentRank, maxRank, _, _ = GetTalentInfo(t, i, isInspect, false, activeTalentGroup)
			currentTree[name] = currentRank
		end
	end
	
	-- Record the maximum health and power of the target.
	target.maxHealth = UnitHealthMax(target.unitId)
	target.maxPower = UnitPowerMax(target.unitId)
	
	-- Flag the target as inspected.
	target.inspected = true
	-- Infer the player's role from his talent points.
	self:InferPlayerRole(target)
end

-- Infer the player role from his talent point distribution and his class.
function Orunj:InferPlayerRole(target)
	target.role = self.classes[target.class]:GetRole(target)
	print("target role: " .. target.role)
end